        TITL DAI FIRMWARE 3EC45-3EDF8  V1.1
        ORG   :EC45
*
*
*
**********************
* COMPARE DE WITH HL *
**********************
*
* Exit: AF corrupted, BCDEHL preserved.
*       HL > DE : A=-1, CY=1, Z=0, S=1.
*       HL = DE : A= 0, CY=0, Z=1, S=0.
*       HL < DE : A= 1, CY=0, Z=0, S=0.
*
L3E194  MOV   A,E
        SUB   L
        MOV   A,D
        SBB   H
        SBB   A
        RM              If HL>DE: A=1, S=1
        MOV   A,E
        XRA   L
        PUSH  D
        MOV   E,A
        MOV   A,D
        XRA   H
        ORA   E
        POP   D
        STC
        RZ              If HL=DE: A=0, Z=CY=1
        XRA   A
        INR   A
        RET             If HL<DE: A=1, CY=0
*
************************************
* DECREMENT HL, COMPARE HL WITH DE *
************************************
*
* HL = HL - 1.
*
* Exit: AF corrupted, BCDEHL preserved.
*       HL was 0: CY=1, Z=1.
*       Else:     New HL > DE : CY=0.
*                 New HL = DE : Z=1.
*                 New HL < DE : CY=1.
*
L3E195  DCX   H
        MOV   A,H
        ANA   L
        ADI   :01
        RC              Ready if old HL was 0
        MOV   A,L       )
        SUB   E         ) Compare HL - DE
        MOV   A,H       )
        SBB   D         )
        RET
*
*************************
* RESTORE CPU REGISTERS *
*************************
*
* Restores CPU registers AFBCDEHL and PC.
* Continues at PC address.
* Stackpointer, TICC and GIC are not restored !
*
L3E196  CALL  :EDE7     Exchange bytes in reg.
 REM save area
L3E197  LHLD  :0053     Get stored PSW
        PUSH  H
        POP   PSW       Restore PSW
        LHLD  :0055
        MOV   B,H
        MOV   C,L       Restore BC
        LHLD  :0057
        XCHG            Restore DE
        LHLD  :005D
        PUSH  H         Addr next instr on stack
        LHLD  :0059     Restore HL
        RET             Goto addr in (005D/E)
*
*********************
* CALCULATE DE - HL *
*********************
*
* Exit: HL = DE - HL.
*       BCDE preserved, AF corrupted.
*
L3E198  MOV   A,E
        SUB   L
        MOV   L,A       L=E-L
        MOV   A,D
        SBB   H
        MOV   H,A       H=D-H-CY
        RET
*
************
* M - MOVE *
************
*
* Moves a block of data (laddr - haddr) given to
* a given destination address (daddr).
*
* Exit: BC: 1st unused destination address.
*       DE: Last source address for direction of
*           movement.
*       HL: 1st unused source address.
*       AF: Corrupted.
*
MOVEK   MVI   C,:03     Nr of addr allowed
        CALL  :EADE     Get addr on stack
        DCR   C         3 addr given ?
        JP    :EA62     Error if not
        POP   B         daddr in BC
        POP   D         haddr in DE
        POP   H         laddr in HL
        PUSH  H         Save laddr on stack
        CALL  :EC7C     Calc length of block to
 REM be moved
        JC    :EA62     Error if wrong inputs
        XTHL            laddr in HL, length on stack
        MOV   A,C       )
        SUB   L         ) Check if daddr < laddr
        MOV   A,B       )
        SBB   H         )
        JC    :ECAE     Then jump
 REM
* If daddr > laddr:
 REM
        XTHL            length in HL, laddr on stack
        DAD   B         daddr of highest byte
        MOV   B,H       ) Store it in BC
        MOV   C,L       )
        POP   H         laddr in HL
        XCHG            DE: laddr, HL: haddr
L3E200  MOV   A,M       Get byte to be moved
        STAX  B         Move it
        DCX   B         Decr pntr daddr
        CALL  :EC58     Check if ready
        RC              Then quit
        JMP   :ECA4     Next byte
 REM
* If daddr < laddr:
 REM
L3E201  XTHL            Length in HL, laddr on stack
        POP   H         laddr in HL
L3E202  MOV   A,M       Get byte
        STAX  B         And move it
        INX   B         Incr pntr daddr
        CALL  :ED80     INX H; check if ready
        RC              Then quit
        JMP   :ECB0     Next byte
*
*************
* Z - RESET *
*************
*
* Z1: Reset CPU save area 0051-005E. Initialise
*     stackpointer to F900 and save it in 005B/C.
*
* Z2: Sets: current interrupt mask (005F) = #C5,
*           TICC control word (0060) = #FC,
*           GIC  control word (0061) = #1B.
*     Initialises interrupt vector area #0062-#0071.
*     Sets interrupt vector RST 0 to #EB5D.
*
* Z3: Z1 + Z2.
*
* Exit: All registers corrupted.
*
ZEROK   MVI   C,:01     Nr of databytes allowed
        CALL  :EADE     Get hexnr and store it
 REM on stack
        POP   H         Get hexnr from stack
        MOV   A,L       into A
        PUSH  PSW       Save it again
        ANI   :02
        JZ    :ECE9     Jump if Z1 only
 REM
* If Z2 or Z3:
 REM
        MVI   A,:C5     Set interrupt mask for
 REM clock, keyb, ext, timer 1
        STA   :005F     Preserve int.mask
        MVI   A,:F4
        NOP
        NOP
        NOP
        ORI   :08
        LXI   H,:0060
        MOV   M,A       Set TICC contr.word = FC
        INX   H
        MVI   M,:1B     Set GIC contr.word = 1B
        CALL  :D91E     Init int.vector addr
        LXI   H,:EB5D
        SHLD  :0062     Set RST0 vector = EB5D
        NOP
        NOP
        NOP
        NOP
        NOP
L3E204  NOP
ZERO1   POP   PSW       Get nr Z instr back
        RAR             Check for Z2 only
        RNC             Ready if Z2 only
 REM
* If Z1 or Z3:
 REM
        MVI   C,:00     )
        LXI   D,:005E   ) Init reg. save area:
        LXI   H,:0051   )
        CALL  :ED54     ) Fill (0051-005E) with 00
        LXI   H,:F900
        SPHL            Set SP=F900
        SHLD  :005B     Save SP
        JMP   :EA42     Return for new inputs
*
***************
* PRINT SPACE *
***************
*
* Exit: AFC corrupted, BDEHL preserved.
*
*TSP
LSP     MVI   C,:20
        JMP   :EEB4     Print space
*
**********************************
* SCAN KEYBOARD, PRINT CHARACTER *
**********************************
*
* Gets a keyboard input. Zeroes are ignored.
* The character is printed (if not 'ESC').
*
* Exit: A : Character typed in.
*       Other registers preserved.
*
CIE     CALL  :EEB8     Scan keyboard
        ANI   :7F       Skip bit 7
        JZ    :ED06     Ignore zeroes (await an
 REM input)
        CPI   :12       'ESC' ?
        PUSH  B
        MOV   C,A       Char in C
        CNZ   :EEB4     Print char if not 'ESC'
        MOV   A,C       Char in A
        POP   B
        RET
*
*
**************************
* PRINT ADDRESS IN ASCII *
**************************
*
* LADDR: An address in HL is converted to ASCII and
*        printed (4 nibbles).
* LBYTE: A 1-byte value is printed in ASCII.
*
* Entry: LADDR: Address in HL.
*        LBYTE: Value in A.
* Exit:  AFC corrupted, BDEHL preserved.
*
LADDR   MOV   A,H       Hibyte in A.
        CALL  :ED1D     Print both nibbles in ASCII
        MOV   A,L       Lobyte in A
LBYTE   PUSH  PSW       Preserve hex value 2 char
        RLC             )
        RLC             ) Move hinibble
        RLC             ) into lonibble
        RLC             )
        CALL  :ED26     Print lonibble
        POP   PSW       Restore byte
L3E210  ANI   :0F       Lonibble only
        CALL  :ED40     Convert it to ASCII
        MOV   C,A       And store it in C
        JMP   :EEB4     Print char in C
*
****************
* PRINT STRING *
****************
*
* Entry: HL points to string. End of string is 00.
* Exit:  HL points to 00 at end of string.
*        AFC corrupted, BDE preserved.
*
L3E211  MOV   A,M       Get byte from string
        MOV   C,A       into C
        ORA   A         Byte = 00 ?
        RZ              Then ready
        CALL  :EEB4     Print char in C
        INX   H         Pnts to next char
        JMP   :ED2F     Print next char
*
*************************
* PRINT CARRIAGE RETURN *
*************************
*
* Exit: AFC corrupted, BDEHL preserved.
*
LCRLF   MVI   C,:0D
        CALL  :EEB4     Print 'CR'
        RET
*
*******************************
* CONVERT HEX NIBBLE TO ASCII *
*******************************
*
* Entry: Hex value in A.
* Exit:  ASCII value in A.
*        BCDEHL preserved. F corrupted.
*
L3E213  ADI   :30       Convert
        CPI   :3A       Number 0-9?
        RC              Then ready
        ADI   :07       Convert A-F
        RET
*
************
* F - FILL *
************
*
* Fills a memory area between given boundaries
* with given data.
*
* Exit: CY=1. All registers corrupted.
*
FILLK   MVI   C,:03     Nr of addr/data allowed
        CALL  :EADE     Get addr/data on stack
        DCR   C         3 blocks given?
        JP    :EA62     Error if not
        POP   B         Data in C
        POP   D         haddr in DE
        POP   H         laddr in HL
FILL    MOV   M,C       Data into memory
        CALL  :ED80     INX H; check if ready
        RC              Then quit
        JMP   :ED54     Fill next addr
*
******************
* S - SUBSTITUTE *
******************
*
SUBSK   MVI   C,:01     Nr of addr allowed
        CALL  :EADE     Get addr on stack
        POP   H         Addr in HL
        MOV   A,M       Get contents of addr
        CALL  :ED1D     Print it in ASCII
        XRA   A
        CALL  :EE6A     Evt. modify contents
        JNC   :ED62     Next addr
        RET
*
***************
* X - EXAMINE *
***************
*
EXAMK   LXI   H,:EE9D   Startaddr register table
        LXI   D,:0053   Startaddr CPU save area
        JMP   :EE39     Go to display routine
*
**********************
* V - VECTOR EXAMINE *
**********************
*
VECXK   LXI   H,:EEA8   Startaddr vector table
        LXI   D,:005F   Startaddr vector area
        JMP   :EE39     Go to display routine
*
************************************
* INCREMENT HL AND COMPARE WITH DE *
************************************
*
* Exit: HL was FFFF: CY=1, Z=1.
*       Else: New HL < DE : CY=0.
*             New HL = DE :  Z=1.
*             New HL > DE : CY=1.
*       BCDE preserved, HL=HL+1, AF corrupted.
*
INXCK   INX   H
        STC             CY=1
        MOV   A,H
        ORA   L
        RZ              Abort if new HL is 0000
        MOV   A,E
        SUB   L
        MOV   A,D
        SBB   H
        RET
*
**********
* G - GO *
**********
*
* Reads one field if given.
* If no field given: Restores CPU registers, goes
*    to PC address. Returnaddress is #EA42 (into
*    command loop).
* If field given: Saves it as PC, initialises TICC
*    and GIC. Returnaddress is #EA04. Goes to the
*    given address.
* REMARK: The stackpointer is never restored !
*
GOK     MVI   C,:01
        CALL  :EB07     Scan keyb; addr on stack
        DCR   C         No addr given?
        PUSH  PSW
        CZ    :EB56     Then check if 'CR'
        POP   PSW
        JZ    :EC63     No addr: restore CPU reg
 REM (but not SP/TICC/GIC !) and
 REM go to addr in 005D/E
        POP   H         'GO' addr in HL
        SHLD  :005D     Save it
L3E221  LHLD  :0060     Get GIC/TICC init values
        MOV   A,H       GIC init value in A
        CALL  :EDD5     Init GIC
        MOV   A,L       TICC init value in A
        CALL  :EDB7     Init TICC
        LDA   :005F     Get current int mask
        STA   :FFF8     Set int mask
        CALL  :EDE7     exch. bytes in 0051-5E
        LXI   H,:EA04   Returnaddr for 'GO'
        PUSH  H         Save EA04 on stack
        JMP   :EC66     Restore CPU reg and 'GO'
*
* INITIALISE TICC:
*
* Entry: A: Initial value TICC command word (#FC).
* Exit:  AFBC corrupted, DEHL preserved.
*
L3E222  MOV   B,A       Init.value in B
        RLC             A=F9
        PUSH  PSW       On stack: A=F9, CY=1
        RLC             A=F3
        RLC             A=E7
        RLC             A=CF
        ANI   :07       A=07
        MOV   C,A       C=07
        XRA   A         A=0
        STC             CY=1
L3E223  RAL             ) On exit: A=80,
        DCR   C         ) C=FF, CY=0
        JP    :EDC2     )
        MOV   C,A       C=80
        POP   PSW       A=F9, CY=1
        MOV   A,C       A=80
        RAR             A=C0
        STA   :FFF5     Set comm.rate reg for 9600
 REM baud, 1 stop bit
        MOV   A,B       A=FC
        ANI   :0F       A=0C
        STA   :FFF4     Set cmd reg for IN7, INTA
 REM enable
        RET
*
* INITIALISE GIC:
*
* This initialisation cancels the initial setting
* done during 'power-on' by 3EF90. Only used during
* 'GO'.
* There seems to be some bug in the routine. All
* ports are set to input, and then data is written
* into one of this ports (PB - FE01). The function
* of L3E225 is nonsense (?!).
*
* Entry: A: Initial value GIC command word (#1B).
* Exit:  AFBC corrupted, DEHL preserved.
*
L3E224  PUSH  PSW       Init value on stack, CY=0
        LXI   B,:FE03   Addr command word
        ORI   :80       A=9B
        STAX  B         Set all ports to input
        DCR   C         BC=FE02
        POP   PSW       A=1B, CY=0
        RLC             A=36, CY=0
        SBB   A         A=0
L3E225  DCX   B         BC=FE01
        STAX  B         (FE01)=00 (?!)
        DCR   C         BC=FE00
        JP    :EDE0     Writes 00 in non-existing
 REM address FDFE (?!)
        RET
*
****************************************
* EXCHANGE BYTES IN REGISTER SAVE AREA *
****************************************
*
* The hibytes and the lobytes of the addresses
* 0053/0054 thru 0059/5A are exchanged which
* each other.
*
* Exit: AFBCHL corrupted. DE preserved.
*
L3E238  LXI   H,:0053   Startaddr
        MVI   A,:04     Nr of addr to be exchanged
L3E226  MOV   B,M       1st byte in B
        INX   H         Pnts to next location
        MOV   C,M       2nd byte in C
        MOV   M,B       1st byte in 2nd location
        DCX   H
        MOV   M,C       2nd byte in 1st location
        INX   H
        INX   H         Points to next addr
        DCR   A         Update counter
        JNZ   :EDEC     Next addr if not ready
        RET
*
*
*
        UNL
TSP     EQU LSP
        LST
        END
